package com.errol.generic.file.excel.service;

import com.renjia.service.generic.file.core.pojo.FileResolvedCode;
import com.renjia.service.generic.file.core.pojo.Filepath;
import com.renjia.service.generic.file.excel.model.ExcelDynamicColumn;
import com.renjia.service.generic.file.excel.model.ExcelResolved;
import com.renjia.service.generic.file.excel.pojo.ExcelColConfig;
import com.renjia.service.generic.file.excel.pojo.ExcelConfig;
import com.renjia.service.generic.file.excel.pojo.ExcelValidator;
import org.springframework.lang.NonNull;

import java.util.List;
import java.util.Map;

/**
 * Created by Errol1017 on 2018/6/13.
 *
 * @author zhang xiao bin
 * @version v1.0
 * @date 2020/10/21
 * @since v4.7.6
 */
public interface ExcelService {

    /**
     * 解析 excel 文件，返回指定对象的 list ，主要执行流程如下：
     * 1 检查文件类型、文件是否存在
     * 2 依据 {@param clazz} 的定义检查数据格式
     * 3 解析 excel ，生成 {@param clazz} 的对象，并使用 Hibernate Validator 进行验证
     * 4 返回解析成功 {@link FileResolvedCode#OK} ，注意：解析成功也可能返回错误文件
     *
     * @param from  excel 文件相对路径，支持多个文件、多张 sheet ，但每个 sheet 都必须是相同的数据解构
     * @param clazz sheet 对应的封装类型，必须使用{@link ExcelConfig} 和{@link ExcelColConfig} 注解定义
     * @param <R>   解析 excel 返回的封装类型
     * @return 解析结果，所有可能的返回值请查看 {@link ExcelResolved} 对象
     * @throws Exception 解析过程中的异常
     */
    <R> ExcelResolved<R> readFromExcel(@NonNull String from, @NonNull Class<R> clazz) throws Exception;

    /**
     * 解析 excel 文件，返回指定对象的 list ，主要执行流程如下：
     * 1 检查文件类型、文件是否存在
     * 2 依据 {@param clazz} 的定义检查数据格式
     * 3 解析 excel ，生成 {@param clazz} 的对象，并使用 Hibernate Validator 进行验证
     * 4 返回解析成功 {@link FileResolvedCode#OK} ，注意：解析成功也可能返回错误文件
     *
     * @param from           excel 文件相对路径，支持多个文件、多张 sheet ，但每个 sheet 都必须是相同的数据解构
     * @param clazz          sheet 对应的封装类型，必须使用{@link ExcelConfig} 和{@link ExcelColConfig} 注解定义
     * @param dynamicSources 动态验证数据源，其中：
     *                       key      为 {@link ExcelColConfig#dynamic()} 的值
     *                       value    为验证 field 的数据源，要求 Map<String, String> 格式，其中：
     *                              key    为 excel 中的字符
     *                              value  为 key 映射的值
     *                       key 如果验证通过，将会 替换为 value 的值，然后执行 setter
     * @param <R>            解析 excel 返回的封装类型
     * @return 解析结果，所有可能的返回值请查看 {@link ExcelResolved} 对象
     * @throws Exception 解析过程中的异常
     */
    <R> ExcelResolved<R> readFromExcel(@NonNull String from, @NonNull Class<R> clazz, @NonNull Map<String, Map<String, String>> dynamicSources) throws Exception;

    /**
     * 解析 excel 文件，返回指定对象的 list ，主要执行流程如下：
     * 1 检查文件类型、文件是否存在
     * 2 依据 {@param clazz} 的定义检查数据格式
     * 3 解析 excel ，生成 {@param clazz} 的对象，并使用 Hibernate Validator 进行验证
     * 4 返回解析成功 {@link FileResolvedCode#OK} ，注意：解析成功也可能返回错误文件
     *
     * @param from           excel 文件相对路径，支持多个文件、多张 sheet ，但每个 sheet 都必须是相同的数据解构
     * @param clazz          sheet 对应的封装类型，必须使用{@link ExcelConfig} 和{@link ExcelColConfig} 注解定义
     * @param excelValidator 表格行验证接口，用来执行复杂的数据验证，其中：
     *                       {@link ExcelValidator#reviewRowData(R r)} 接受 {@param clazz} 封装的对象
     *                       返回 null|'' 表示验证通过；返回 字符串 表示验证失败的错误信息，该字符串将在 错误文件中输出
     * @param <R>            解析 excel 返回的封装类型
     * @return 解析结果，所有可能的返回值请查看 {@link ExcelResolved} 对象
     * @throws Exception 解析过程中的异常
     */
    <R> ExcelResolved<R> readFromExcel(@NonNull String from, @NonNull Class<R> clazz, @NonNull ExcelValidator<R> excelValidator) throws Exception;

    /**
     * 解析 excel 文件，返回指定对象的 list ，主要执行流程如下：
     * 1 检查文件类型、文件是否存在
     * 2 依据 {@param clazz} 的定义检查数据格式
     * 3 解析 excel ，生成 {@param clazz} 的对象，并使用 Hibernate Validator 进行验证
     * 4 返回解析成功 {@link FileResolvedCode#OK} ，注意：解析成功也可能返回错误文件
     *
     * @param from           excel 文件相对路径，支持多个文件、多张 sheet ，但每个 sheet 都必须是相同的数据解构
     * @param clazz          sheet 对应的封装类型，必须使用{@link ExcelConfig} 和{@link ExcelColConfig} 注解定义
     * @param dynamicSources 动态验证数据源，其中：
     *                       key      为 {@link ExcelColConfig#dynamic()} 的值
     *                       value    为验证 field 的数据源，要求 Map<String, String> 格式，其中：
     *                              key    为 excel 中的字符
     *                              value  为 key 映射的值
     *                       key 如果验证通过，将会 替换为 value 的值，然后执行 setter
     * @param excelValidator 表格行验证接口，用来执行复杂的数据验证，其中：
     *                       {@link ExcelValidator#reviewRowData(R r)} 接受 {@param clazz} 封装的对象
     *                       返回 null|'' 表示验证通过；返回 字符串 表示验证失败的错误信息，该字符串将在 错误文件中输出
     * @param <R>            解析 excel 返回的封装类型
     * @return 解析结果，所有可能的返回值请查看 {@link ExcelResolved} 对象
     * @throws Exception 解析过程中的异常
     */
    <R> ExcelResolved<R> readFromExcel(@NonNull String from, @NonNull Class<R> clazz, @NonNull Map<String, Map<String, String>> dynamicSources,
                                       @NonNull ExcelValidator<R> excelValidator) throws Exception;

    /**
     * 将数据写入 excel 文件
     *
     * @param data  待写入数据
     * @param toDir 写入操作的目标文件夹
     * @param clazz sheet 对应的封装类型，必须使用{@link ExcelConfig} 和{@link ExcelColConfig} 注解定义
     * @param <R>   待写入数据解构和 sheet 对应的封装类型
     * @return 生成的 excel 文件路径
     * @throws Exception 解析过程中的异常
     */
    <R> String writeToExcel(@NonNull List<R> data, @NonNull Filepath toDir, @NonNull Class<R> clazz) throws Exception;

    /**
     * 将数据写入 excel 文件，允许动态定义 excel 列
     *
     * @param header 动态定义的 excel 列
     * @param data   excel 数据
     * @param toDir  写入操作的目标文件夹
     * @return 生成的 excel 文件路径
     * @throws Exception 解析过程中的异常
     */
    String writeToExcel(@NonNull List<ExcelDynamicColumn> header, @NonNull List<List<Object>> data, @NonNull Filepath toDir) throws Exception;

    /**
     * 将数据写入 excel 文件，允许动态定义 excel 列
     *
     * @param header 动态定义的 excel 列
     * @param data   excel 数据
     * @param toDir  写入操作的目标文件夹
     * @param title  excel 标题
     * @return 生成的 excel 文件路径
     * @throws Exception 解析过程中的异常
     */
    String writeToExcel(@NonNull List<ExcelDynamicColumn> header, @NonNull List<List<Object>> data, @NonNull Filepath toDir, @NonNull String title) throws Exception;
}
